using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using CthulhuDomain.GameEntities;
using CthulhuDomain.Services;
using CthulhuDomain.Strategies;
using Microsoft.Xna.Framework;

namespace CthulhuDomain.GameEntities
{
  public sealed class Cthulhu : DomainEntity
  {
    public Cthulhu() {
      pos = new Vector2Adapter(0, 0);
      //FrameColumns = 19;
      FrameColumns = 1;
      Shoots = new List<DomainEntity>();
      PowerUps = new List<DomainEntity>();
      Score = new Score(1000);
    }

    public Cthulhu(IVector2 position) {
      pos = position;
      //FrameColumns = 19;
      FrameColumns = 1;
      Shoots = new List<DomainEntity>();
      PowerUps = new List<DomainEntity>();
      Score = new Score(1000);
    }

    #region

    private int _height = 31;
    public override int Height {
      get { return _height; }
      set { _height = value; }
    }

    private int _width = 50;
    public override int Width {
      get { return _width; }
      set { _width = value; }
    }

    private float speed = 2f;

    public override float Speed {
      get { return speed; }
      set { speed = value; }
    }

    public override IVector2 Position {
      get { return pos; }
      set {
        var oldPos = pos;
        pos = value;
        if (pos.Y > oldPos.Y && Score.Amount > 200) {
          Score.Amount -= 100;
        }
      }
    }

    protected override int Mpf {
      get { return 190; }
    }

    public override int Damage {
      get { return 3; }
    }

    public IContentManager ContentManager { get; set; }

    #endregion


    public override void Update(IRectangle context, IGameTime time) {
      RemoveEntityOutOfContext();
      foreach (var item in Shoots.Where(item => item != null)) {
        item.Speed = BulletSpeed;
        item.Move(context);
      }

      foreach (var item in PowerUps.Where(item => item != null))
        item.Move(context);


      timeSinceLastFrame += time.ElapsedGameTime.Milliseconds;

      if (timeSinceLastFrame <= Mpf) return;
      timeSinceLastFrame -= Mpf;
      ++CurrentFrame;

    }

    public override void Draw(ISpriteBatch spriteBatch) {
      Draw(spriteBatch, ColorByLifePoint(LifePoint), (float)1, 1);

      RemoveEntityOutOfContext();

      foreach (var item in Shoots.Where(item => item != null))
        item.Draw(spriteBatch);

      foreach (var item in PowerUps.Where(item => item != null))
        item.Draw(spriteBatch, new ColorAdapter(Color.White));
    }

    internal override void AddShoot() {

      var s = new Shoot(new Vector2Adapter(Position.X, Position.Y + Height)) { Texture = ProtoTypeChild.Texture };
      s.MovementStrategy = new VerticalMovement(s, eDirection.Down);
      CollisionManager.AddShoot(s);

    }

    internal override void AddPowerUp() {
      var type = (PowerUpFactory.ePowerUp)StaticRandomNumberGenerator.RandomNext(1, 9);
      var factory = PowerUpFactory.GetFactory(type);
      var powerUp = factory.CreatePowerUp(ContentManager);
      powerUp.Position = new Vector2Adapter(Position.X, Position.Y + Height);
      var texture = TextureByType(ContentManager, type);
      powerUp.Texture = texture;
      powerUp.MovementStrategy = new VerticalMovement(powerUp, eDirection.Down);

      CollisionManager.AddPowerUp(powerUp);
    }

  }

  public static class StaticRandomNumberGenerator
  {
    private static readonly RandomNumberGenerator RandomGenerator = RandomNumberGenerator.Create();
    public static int RandomNext(int min, int max) {
      if (min > max) throw new ArgumentOutOfRangeException("min");

      var bytes = new byte[4];

      RandomGenerator.GetBytes(bytes);

      var next = BitConverter.ToUInt32(bytes, 0);

      var range = max - min;

      return (int)((next % range) + min);
    }
  }

  //TODO move following implementation to another file
  #region Power implementations

  public interface IPowerImplementator
  {
    void Execute(ref DomainEntity player, ref DomainEntityMatrix army);

    string TextMessage { get; set; }
  }

  public abstract class PowerImplementator : IPowerImplementator
  {
    public enum eTargetEntity
    {
      None = 0,
      Player = 1,
      Army = 2
    }

    protected PowerUpFactory.ePowerUp typePowerUp;
    protected eTargetEntity targetEntity;
    public abstract void Execute(ref DomainEntity player, ref DomainEntityMatrix army);

    public string TextMessage {
      get;
      set;
    }
  }

  internal class BulletSpeedImplementator : PowerImplementator
  {
    public BulletSpeedImplementator(eTargetEntity target, PowerUpFactory.ePowerUp type) {
      typePowerUp = type;
      targetEntity = target;
    }

    public override void Execute(ref DomainEntity player, ref DomainEntityMatrix army) {
      switch (typePowerUp) {
        case PowerUpFactory.ePowerUp.Army_Bullet_Speed:
        case PowerUpFactory.ePowerUp.Player_Bullet_Speed:
          switch (targetEntity) {
            case eTargetEntity.Player:
              player.BulletSpeed += 1;
              break;
            case eTargetEntity.Army:
              CollisionManager.CurrentStage.BulletSpeed += 1;
              break;
          }
          break;
        case PowerUpFactory.ePowerUp.Army_Bullet_Slow:
        case PowerUpFactory.ePowerUp.Player_Bullet_Slow:
          switch (targetEntity) {
            case eTargetEntity.Player:
              if (player.BulletSpeed > 1)
                player.BulletSpeed -= 1;
              break;
            case eTargetEntity.Army:
              if (CollisionManager.CurrentStage.BulletSpeed > 1)
                CollisionManager.CurrentStage.BulletSpeed += 1;

              break;
          }
          break;
      }
    }
  }

  internal class EntitySpeedImplementator : PowerImplementator
  {
    public EntitySpeedImplementator(PowerImplementator.eTargetEntity target, PowerUpFactory.ePowerUp type) {
      typePowerUp = type;
      targetEntity = target;
    }

    public override void Execute(ref DomainEntity player, ref DomainEntityMatrix army) {
      switch (typePowerUp) {
        case PowerUpFactory.ePowerUp.Army_Speed:
        case PowerUpFactory.ePowerUp.Player_Speed:
          switch (targetEntity) {
            case eTargetEntity.Player:
              player.Speed += 1;
              break;
            case eTargetEntity.Army:
              army.Speed += 1;
              break;
          }
          break;
        case PowerUpFactory.ePowerUp.Army_Slow:
        case PowerUpFactory.ePowerUp.Player_Slow:
          switch (targetEntity) {
            case eTargetEntity.Player:
              if (player.Speed > 2)
                player.Speed -= 1;
              break;
            case eTargetEntity.Army:
              if (army.Speed > 2)
                army.Speed -= 1;
              break;
          }
          break;
      }
    }
  }

  internal class PlayerLifeImplementator : PowerImplementator
  {
    public override void Execute(ref DomainEntity player, ref DomainEntityMatrix army) {
      player.LifePoint += 1;
    }
  }

  #endregion

}
